package com.visu.common.jwt;

import com.visu.common.utils.MD5Util;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.time.DateUtils;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;


/**
 * 生成token的工具类
 *
 * @author 程振奇
 */
public class JWTUtils {

    /**
     * 设置加密算法
     */
    private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    private Key key;
    private String base64Security = MD5Util.string2MD5("visu");

    public JWTUtils() {

        key = init();
    }

    public JWTUtils(String base64Security) {
        this.base64Security = base64Security;
        key = init();
    }

    /**
     * 创建jwt token
     *
     * @param parameter      需要添加的参数
     * @param expirationType 过期周期类型 年 月 日 时 分 秒 按照Calendar 常量来
     * @param period         周期 例如 1年 2年 1个月 2个月
     * @return
     */
    public String createJWT(Map<String, Object> parameter, Integer expirationType, Integer period) {
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setClaims(parameter)
                .signWith(signatureAlgorithm, key);
        // 添加Token过期时间

        if (expirationType != null) {
            Date now = new Date();
            switch (expirationType) {
                case Calendar.YEAR:
                    builder.setExpiration(DateUtils.addYears(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                case Calendar.MONTH:
                    builder.setExpiration(DateUtils.addMonths(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                case Calendar.DATE:
                    builder.setExpiration(DateUtils.addDays(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                case Calendar.HOUR:
                    builder.setExpiration(DateUtils.addHours(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                case Calendar.MINUTE:
                    builder.setExpiration(DateUtils.addMinutes(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                case Calendar.SECOND:
                    builder.setExpiration(DateUtils.addSeconds(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
                default:
                    builder.setExpiration(DateUtils.addMonths(now, period == null ? 1 : period)).setNotBefore(now);
                    break;
            }
        }
        // 生成JWT
        return builder.compact();

    }

    /**
     * 创建jwt
     *
     * @param parameter
     * @param expirationType
     * @return
     */
    public String createJWT(Map<String, Object> parameter, Integer expirationType) {
        return createJWT(parameter, expirationType, null);
    }

    public String createJWT(Map<String, Object> parameter) {
        return createJWT(parameter, null, null);
    }


    /**
     * 解析jwt
     */
    public Claims parseJWT(String jwtToken) throws Exception {
        JwtParser signingKey = Jwts.parser().setSigningKey(key);
        Jws<Claims> claimsJws = signingKey.parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return claims;

    }

    /**
     * 校验token
     *
     * @param jwtToken
     * @return
     */
    public JWTResultBean checkJWT(String jwtToken) {
        try {
            parseJWT(jwtToken);
            JWTResultBean jwtResultBean = new JWTResultBean();
            jwtResultBean.setSuccess(true);
            return jwtResultBean;
        } catch (Exception e) {
            if (e instanceof ExpiredJwtException) {
                JWTResultBean jwtResultBean = new JWTResultBean();
                jwtResultBean.setSuccess(false);
                jwtResultBean.setErrorMsg("token已过期");
                return jwtResultBean;
            } else {
                JWTResultBean jwtResultBean = new JWTResultBean();
                jwtResultBean.setSuccess(false);
                jwtResultBean.setErrorMsg("token校验失败");
                return jwtResultBean;
            }
        }

    }




    /**
     * 生成签名秘钥的方法
     */
    private Key init() {
        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        return signingKey;
    }
}